import mongoengine as me
from mongoengine.base.metaclasses import DocumentMetaclass


# Parameter object in Api.params
# Mappings to OpenAPI 3.0 Spec:
# name -> parameters.[].name
# param_in -> parameters.[].in (the location of the parameter, possible values
#               are 'query', 'header', 'path' or 'cookie')
# param_type -> parameters.[].schema.type (as a naive version, possible
#               values include: number, string, boolean)
# description -> parameters.[].description
class Param(me.EmbeddedDocument):
    name = me.StringField(required=True)
    param_in = me.StringField(required=True, db_field='in')
    param_type = me.StringField(required=True, db_field='type')
    description = me.StringField()


# Schema object in Response.schema
# Mappings to OpenAPI 3.0 Spec:
# schema_type -> schema.type (possible values include: number, string, boolean,
#                   object, array)
# properties -> schema.properties (subschemas for object type schema)
# items -> schema.items (items MUST be present if the type is array.)
class Schema(me.EmbeddedDocument):
    schema_type = me.StringField(required=True, db_field='type')
    properties = me.DynamicField()
    items = me.DynamicField()


# Response object in Api.responses
# Note: supports response object with media type application/json only for now
# Mappings to OpenAPI 3.0 Spec:
# description -> responses.{HTTPStatusCode}.description
# schema -> responses.{HTTPStatusCode}.content.application/json.schema
class Response(me.EmbeddedDocument):
    description = me.StringField()
    schema = me.EmbeddedDocumentField(Schema, default=None)


# API in Image.api_list
# Mappings to OpenAPI 3.0 Spec:
# name -> paths.{path}.{method}.operationId
# path -> paths.{path}
# method -> paths.{path}.{method}
# params -> paths.{path}.{method}.parameters
# responses -> paths.{path}.{method}.responses
class Api(me.EmbeddedDocument):
    name = me.StringField(required=True)
    path = me.StringField(required=True)
    method = me.StringField(required=True)
    description = me.StringField()
    params = me.EmbeddedDocumentListField(Param, default=None)
    responses = me.EmbeddedDocumentListField(Response, default=None)


# a docker image, the equivalent of a kind of service
class Image(me.Document):
    image_id = me.StringField(required=True, db_field='id')
    name = me.StringField(required=True)
    source = me.StringField(required=True)
    description = me.StringField(required=True)
    api_list = me.EmbeddedDocumentListField(Api, default=[], db_field='apis')


# attribute for instance
class Attribute(me.EmbeddedDocument):
    key = me.StringField(required=True)
    path = me.StringField(required=True)


# one instance, one device
class Instance(me.Document):
    # dont need a unique id, use namespace + name to query
    namespace = me.StringField(required=True)
    # deployment name
    name = me.StringField(required=True)
    # docker image name
    service = me.StringField(required=True)
    device_number = me.StringField(required=True)
    # the release status of a instance
    publish_status = me.BooleanField(default=False)
    port = me.IntField(default=8080)
    instance_id = me.StringField(required=True)
